﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
//o rly?
namespace SerializedData
{

    /// <summary>
    /// This class holds all states, scenes, commands and sensor.
    /// It also provides methods to load and save this data.
    /// </summary>
    public class DataCollection
    {
        private List<SCommand> mCommandPool = null;
        private List<SScene> mScenePool = null;
        private List<SState> mStatePool = null;
        private List<SSensor> mSensorPool = null;
        private IDController mIdc = null;
        
        private String mFilename;
        private String mFileIdc = "idc";
        private String mFileCommands = "commands";
        private String mFileScenes = "scenes";
        private String mFileStates = "states";
        private String mFileSensors = "sensors";
        private long mCommandInt = 0;
        private long mSceneInt = 0;
        private long mStateInt = 0;

        private static DataCollection mInstance=null;



        public static DataCollection Instance
        {
            get
            {
                if (mInstance == null)
                {
                    mInstance = new DataCollection();
                    mInstance.loadCollection();
                }
                return mInstance;
            }

        }

        public static DataCollection NewInstance
        {
            get
            {
                mInstance = new DataCollection();
                mInstance.loadCollection();
                return mInstance;
            }

        }
        
        private DataCollection() {

            init("..//..//..//..//kbdata//");


            
        }
        public void saveChanges()
        {
            saveCollection();
        }
        private void init(String dataPath)
        {
            System.IO.Directory.CreateDirectory("..//..//..//..//kbdata");
            mFilename = dataPath;
        }
        private bool loadCollection()
        {
            Stream stream;
            BinaryFormatter bFormatter;
            if (!File.Exists(mFilename + mFileCommands) || !File.Exists(mFilename + mFileScenes) || !File.Exists(mFilename + mFileStates) || !File.Exists(mFilename + mFileSensors) || !File.Exists(mFilename + mFileIdc))
            {
                mCommandPool = new List<SCommand>();
                mScenePool = new List<SScene>();
                mStatePool = new List<SState>();
                mSensorPool = new List<SSensor>();
                mIdc = new IDController();
                
                stream = File.Open(mFilename + mFileCommands, FileMode.Create);
                bFormatter = new BinaryFormatter();
                bFormatter.Serialize(stream, mCommandPool);
                stream.Close();

                stream = File.Open(mFilename + mFileScenes, FileMode.Create);
                bFormatter = new BinaryFormatter();
                bFormatter.Serialize(stream, mScenePool);
                stream.Close();

                stream = File.Open(mFilename + mFileStates, FileMode.Create);
                bFormatter = new BinaryFormatter();
                bFormatter.Serialize(stream, mStatePool);
                stream.Close();

                stream = File.Open(mFilename + mFileSensors, FileMode.Create);
                bFormatter = new BinaryFormatter();
                bFormatter.Serialize(stream, mSensorPool);
                stream.Close();

                stream = File.Open(mFilename + mFileIdc, FileMode.Create);
                bFormatter = new BinaryFormatter();
                bFormatter.Serialize(stream, mIdc);
                stream.Close();
            }


            stream = File.Open(mFilename + mFileCommands, FileMode.Open);
            bFormatter = new BinaryFormatter();
            mCommandPool = (List<SCommand>) bFormatter.Deserialize(stream);
            stream.Close();

            stream = File.Open(mFilename + mFileScenes, FileMode.Open);
            bFormatter = new BinaryFormatter();
            mScenePool = (List<SScene>)bFormatter.Deserialize(stream);
            stream.Close();

            stream = File.Open(mFilename + mFileStates, FileMode.Open);
            bFormatter = new BinaryFormatter();
            mStatePool = (List<SState>)bFormatter.Deserialize(stream);
            stream.Close();

            stream = File.Open(mFilename + mFileSensors, FileMode.Open);
            bFormatter = new BinaryFormatter();
            mSensorPool = (List<SSensor>)bFormatter.Deserialize(stream);
            stream.Close();

            stream = File.Open(mFilename + mFileIdc, FileMode.Open);
            bFormatter = new BinaryFormatter();
            mIdc = (IDController)bFormatter.Deserialize(stream);
            stream.Close();

            return true;
        }
        private bool saveCollection() 
        {
            Stream stream;
            BinaryFormatter bFormatter;
            stream = File.Open(mFilename + mFileCommands, FileMode.Create);
            bFormatter = new BinaryFormatter();
            bFormatter.Serialize(stream, mCommandPool);
            stream.Close();

            stream = File.Open(mFilename + mFileScenes, FileMode.Create);
            bFormatter = new BinaryFormatter();
            bFormatter.Serialize(stream, mScenePool);
            stream.Close();

            stream = File.Open(mFilename + mFileStates, FileMode.Create);
            bFormatter = new BinaryFormatter();
            bFormatter.Serialize(stream, mStatePool);
            stream.Close();

            stream = File.Open(mFilename + mFileSensors, FileMode.Create);
            bFormatter = new BinaryFormatter();
            bFormatter.Serialize(stream, mSensorPool);
            stream.Close();

            stream = File.Open(mFilename + mFileIdc, FileMode.Create);
            bFormatter = new BinaryFormatter();
            bFormatter.Serialize(stream, mIdc);
            stream.Close();


            return true;
        }

        public List<SCommand> getCommandPool()
        {
            return mCommandPool;
        }
        public void addCommand(SCommand command) 
        {
            SCommand sCommand = mCommandPool.Find(o => o.getId().Equals(command.getId()));
            if (sCommand == null)
                mCommandPool.Add(command);
        }
        public void modifyOrAddCommand(SCommand command)
        {
            SCommand sCommand = mCommandPool.Find(o => o.getId().Equals(command.getId()));
            if (sCommand != null)
                mCommandPool.Remove(sCommand);
            mCommandPool.Add(command);
        }

        public void modifyOrAddSensor(SSensor sensor)
        {
            SSensor sSensor = mSensorPool.Find(o => o.getId().Equals(sensor.getId()));
            if (sSensor != null)
                mSensorPool.Remove(sSensor);
            mSensorPool.Add(sensor);
        }
        public SSensor getSensorById(String id)
        {
            SSensor sSensor = mSensorPool.Find(o => (""+o.getId()).Equals(id));
            if (sSensor != null)
                return sSensor;
            return new SSensor(getSensorInt(), "", "", "");
        }
        public void removeCommand(SCommand command)
        {
            SCommand sCommand = mCommandPool.Find(o => o.getId().Equals(command.getId()));
            if (sCommand != null)
                mCommandPool.Remove(sCommand);
        }
        public void removeCommandById(String id)
        {
            SCommand sCommand = mCommandPool.Find(o => (""+o.getId()).Equals(id));
            if (sCommand != null)
                mCommandPool.Remove(sCommand);
        }

        public List<SScene> getScenePool()
        {
            return mScenePool;
        }
        public void addScene(SScene scene)
        {
            SScene sScene = mScenePool.Find(o => o.getId().Equals(scene.getId()));
            if (sScene == null)
                mScenePool.Add(scene);
        }
        public void modifyOrAddScene(SScene scene)
        {
            SScene sScene = mScenePool.Find(o => o.getId().Equals(scene.getId()));
            if (sScene != null)
                mScenePool.Remove(sScene);
            mScenePool.Add(scene);
        }
        public void removeScene(SScene scene)
        {
            SScene sScene = mScenePool.Find(o => o.getId().Equals(scene.getId()));
            if (sScene != null)
                mScenePool.Remove(sScene);
        }
        public void removeSceneById(String id)
        {
            SScene sScene = mScenePool.Find(o => (""+o.getId()).Equals(id));
            if (sScene != null)
                mScenePool.Remove(sScene);
        }

        public void removeStateById(String id)
        {
            SState sState = mStatePool.Find(o => ("" + o.getId()).Equals(id));
            if (sState != null)
                mStatePool.Remove(sState);
        }

        public void removeSensorById(String id)
        {
            SSensor sSensor = mSensorPool.Find(o => ("" + o.getId()).Equals(id));
            if (sSensor != null)
                mSensorPool.Remove(sSensor);
        }

        public List<SState> getStatePool()
        {
            return mStatePool;
        }

        public List<SSensor> getSensorPool()
        {
            return mSensorPool;
        }

        public void modifyOrAddState(SState state)
        {
            SState sState = mStatePool.Find(o => o.getId().Equals(state.getId()));
            if (sState != null)
                mStatePool.Remove(sState);
            mStatePool.Add(state);
        }

       
        public long getCommandInt()
        {
            mIdc.CommandId++;
            return mIdc.CommandId;
        }
        public long getSceneInt()
        {
            mIdc.SceneId++;
            return mIdc.SceneId;
        }
        public long getStateInt()
        {
            mIdc.StateId++;
            return mIdc.StateId;
        }

        public long getSensorInt()
        {
            mIdc.SensorId++;
            return mIdc.SensorId;
        }

    }
}
